package xyz.bali16.application.service.impl;

import cn.hutool.core.util.StrUtil;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xyz.bali16.application.config.prop.AuthProp;
import xyz.bali16.application.core.exception.BusinessException;
import xyz.bali16.application.core.utils.AuthUtils;
import xyz.bali16.application.core.utils.IDUtils;
import xyz.bali16.application.entity.*;
import xyz.bali16.application.mapper.RoleMapper;
import xyz.bali16.application.mapper.RoleMenuMapper;
import xyz.bali16.application.mapper.UserMapper;
import xyz.bali16.application.model.role.RoleAddParam;
import xyz.bali16.application.model.role.RoleMenuUpdateParam;
import xyz.bali16.application.model.role.RoleUpdateParam;
import xyz.bali16.application.service.MenuService;
import xyz.bali16.application.service.RoleMenuService;
import xyz.bali16.application.service.RoleService;
import xyz.bali16.application.service.UserRoleService;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;


@Service
@AllArgsConstructor
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    private final RoleMenuService roleMenuService;
    private final UserRoleService userRoleService;

    private final MenuService menuService;

    private final UserMapper userMapper;
    private final AuthProp authProp;


    @Override
    public boolean exist(String roleCode) {
        if (StrUtil.isEmpty(roleCode)) {
            return false;
        }
        Wrapper<Role> wrapper = Wrappers.<Role>lambdaQuery()
                .eq(Role::getCode, roleCode);

        return count(wrapper) > 0;
    }

    @Override
    public synchronized void addRole(RoleAddParam param) throws Exception {
        checkRoleCode(param.getCode());
        Role role = new Role();
        BeanUtils.copyProperties(param, role);
        role.setDeleted(0);
        save(role);
    }

    @Override
    public synchronized void updateRole(RoleUpdateParam param) throws Exception {
        Role role = getById(param.getRoleId());
        if (!Objects.equal(role.getCode(), param.getCode())) {
            checkRoleCode(param.getCode());
        }
        checkSuperRole(role);
        Role updateBean = new Role();
        BeanUtils.copyProperties(param, updateBean);
        updateById(updateBean);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public synchronized void deleteRole(String roleId) throws Exception {
        if (StrUtil.isEmpty(roleId)) {
            return;
        }
        Role role = getById(roleId);
        if (role == null) {
            return;
        }
        checkSuperRole(role);
        // 先删除角色, 再删除关联权限和菜单
        removeById(roleId);
        roleMenuService.removeByRoleId(roleId);
        // 解除该角色对应的用户
        userRoleService.removeByRoleId(roleId);
    }

    @Transactional
    @Override
    public synchronized void updateStatus(String roleId, Integer status) throws Exception {
        if (StrUtil.isEmpty(roleId)) {
            return;
        }
        Preconditions.checkNotNull(status, "状态不能为空");
        Preconditions.checkArgument(status == 0 || status == 1,
                "状态标志错误：" + status);
        Role role = getById(roleId);
        if (role == null) {
            throw new BusinessException("没有发现角色: " + roleId);
        }
        checkSuperRole(role);
        if (Objects.equal(role.getStatus(), status)) {
            return;
        }
        Role updateBean = new Role();
        updateBean.setRoleId(roleId);
        updateBean.setStatus(status);
        updateById(updateBean);
        // 修改角色对应的用户状态
        userMapper.updateStatusByRoleId(roleId, status);
    }

    @Override
    public synchronized void updateRoleMenu(RoleMenuUpdateParam param) throws Exception {
        Role role = getById(param.getRoleId());
        if (role == null) {
            throw new BusinessException("没有发现角色: " + param.getRoleId());
        }
        checkSuperRole(role);
        roleMenuService.removeByRoleId(param.getRoleId());
        Set<Long> menus = param.getMenus();
        if (menus == null || menus.isEmpty()) {
            return;
        }
        List<RoleMenu> roleMenus = menus.stream()
                .map(m -> {
                    RoleMenu roleMenu = new RoleMenu();
                    roleMenu.setId(IDUtils.uuid());
                    roleMenu.setRoleId(param.getRoleId());
                    roleMenu.setMenuId(m);
                    return roleMenu;
                })
                .collect(Collectors.toList());


        Set<Long> parentMenus = param.getParentMenus();
        if (parentMenus != null) {
            for (Long parentMenuId : parentMenus) {
                RoleMenu roleMenu = new RoleMenu();
                roleMenu.setId(IDUtils.uuid());
                roleMenu.setRoleId(param.getRoleId());
                roleMenu.setMenuId(parentMenuId);
                roleMenus.add(roleMenu);
            }
        }

        roleMenuService.saveBatch(roleMenus);
    }


    private void checkSuperRole(Role role) throws Exception {
        String superAdminCode = authProp.getSuperRoleCode();
        if (Objects.equal(superAdminCode, role.getCode())) {
            throw new BusinessException("不能操作超级管理角色");
        }
    }

    private void checkRoleCode(String roleCode) throws Exception {
        if (exist(roleCode)) {
            throw new BusinessException("已经存在角色编号：" + roleCode);
        }
    }

    @Override
    public List<Menu> findMenusByRoleId(String roleId) { //根据角色Id查权限
        return menuService.findMenusByRoleId(roleId);
    }

    @Override
    public void addRoleMenu(String roleId, List<String> menuIdsList) {
        roleMenuService.remove(Wrappers.<RoleMenu>lambdaQuery().eq(RoleMenu::getRoleId, roleId)); // 删掉之前角色的权限
        //这算是覆盖读写 有点蠢 但方便
        for (String menuId : menuIdsList) {
            RoleMenu rolePermisison = new RoleMenu();
            rolePermisison.setRoleId(roleId);
            rolePermisison.setMenuId(Long.valueOf(menuId));
            System.out.println("rolePermisison" + rolePermisison);
            roleMenuService.save(rolePermisison);
        }

    }

    @Override
    public boolean isAdmin(String username) {
        User user = userMapper.getUserByUsername(username);
        LambdaQueryWrapper<Role> wrapper = Wrappers.<Role>lambdaQuery()
                .eq(Role::getCode, authProp.getSuperRoleCode());
        Page<Role> page = new Page<>(1, 100);
        page = page(page, wrapper);
        List<Role> roles = page.getRecords();
        for (Role role : roles) {
            String roleId = role.getRoleId();
            List<UserRole> userRoles = userRoleService.getByRoleId(roleId);
            for (UserRole userRole : userRoles) {
                if (userRole.getUserId().equals(user.getUserId())) {
                    return true;
                }
            }
        }
        return false;
    }
}